package request

import (
	"crypto/tls"
	"io"
	"net"
	"net/http"
	"time"
)

func HttpClient(request *Request) *Response {
	// 复制参数
	method := request.Method
	url := request.URL
	body := request.SetBody()
	timeout := request.Timeout
	headers := request.SetHeaders()

	// 创建request对象
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil
	}

	// 在req中设置Host，解决在header中设置Host不生效问题
	if _, ok := headers["Host"]; ok {
		req.Host = headers["Host"]
	}
	// 设置默认为utf-8编码
	if _, ok := headers["Content-Type"]; !ok {
		if headers == nil {
			headers = make(map[string]string)
		}
		headers["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
	}
	// 设置请求头
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	// 设置客服端参数
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	if request.Keepalive {
		tr.DialContext = (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).DialContext
		tr.MaxIdleConnsPerHost = request.MaxCon // 对每个host的最大连接数量(MaxIdleConnsPerHost<=MaxIdleConns)
		tr.IdleConnTimeout = 90 * time.Second   // 多长时间未使用自动关闭连接
		tr.MaxIdleConns = 0                     // 最大连接数,默认0无穷大
	}
	if request.SSL {
		tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: false}
	}
	req.Close = true

	// 客户端对象
	client := &http.Client{
		Transport: tr,
		Timeout:   timeout,
	}
	if !request.Redirect {
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		}
	}

	// 开始时间
	startTime := time.Now()
	// 发送请求
	response, err := client.Do(req)
	spendTime := time.Since(startTime)
	defer func() {
		if response != nil {
			response.Body.Close()
		}
	}()

	// 返回结果
	resp := &Response{
		Time:       int(spendTime),
		IsSucceed:  true,
		StatusCode: -999,
	}

	if err != nil {
		resp.IsSucceed = false
		resp.StatusCode = ErrRequest
		return resp
	} else {
		respBody, _ := io.ReadAll(response.Body)
		resp.IsSucceed = request.Verify(respBody)
		resp.StatusCode = response.StatusCode
		resp.ReceivedBytes = int(response.ContentLength)
		copy(resp.Cookies, response.Cookies())
	}

	return resp
}
